home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / nan_news / toolkit / dispc.c < prev    next >
C/C++ Source or Header  |  1991-08-17  |  28KB  |  929 lines

  1. /*
  2.  * File......: DISPC.C
  3.  * Author....: Mike Taylor
  4.  * Date......: $Date:   17 Aug 1991 15:25:46  $
  5.  * Revision..: $Revision:   1.3  $
  6.  * Log file..: $Logfile:   E:/nanfor/src/dispc.c_v  $
  7.  * 
  8.  * This is an original work by Mike Taylor and is placed in the
  9.  * public domain.
  10.  *
  11.  * Modification history:
  12.  * ---------------------
  13.  *
  14.  * $Log:   E:/nanfor/src/dispc.c_v  $
  15.  * 
  16.  *    Rev 1.3   17 Aug 1991 15:25:46   GLENN
  17.  * Don Caton fixed some spelling errors in the doc
  18.  * 
  19.  *    Rev 1.2   15 Aug 1991 23:08:14   GLENN
  20.  * Forest Belt proofread/edited/cleaned up doc
  21.  * 
  22.  *    Rev 1.1   14 Jun 1991 19:53:42   GLENN
  23.  * Minor edit to file header
  24.  * 
  25.  *    Rev 1.0   01 Apr 1991 01:02:46   GLENN
  26.  * Nanforum Toolkit
  27.  * 
  28.  *
  29.  */
  30.  
  31.  
  32.  
  33. #include "extend.h"
  34. #include "dfkey.h"
  35.  
  36.  
  37. #define MK_FP(seg, ofs) ((void far *) (((unsigned long)(seg) << 16) | (unsigned)(ofs)))
  38.  
  39. #define FP_SEG(fp) (*((unsigned *)&(fp) + 1))   // copied from MSC 5.1
  40. #define FP_OFF(fp) (*((unsigned *)&(fp)))       //  include file 'dos.h'
  41.  
  42. #define OFF 0
  43. #define ON  (!OFF)
  44. #define NO  0
  45. #define YES (!NO)
  46. #define OK  0
  47.  
  48. #define CR   ((char) 13)
  49. #define LF   ((char) 10)
  50. #define FEOF ((char) 26)
  51.  
  52. #define SEEK_END 2              // file seek directions
  53. #define SEEK_CUR 1
  54. #define SEEK_SET 0
  55.  
  56. #define READONLY  0             // open file modes
  57. #define WRITEONLY 1
  58. #define READWRITE 2
  59.  
  60. #define MDASEG 0x0b000          // mono video memory segment
  61. #define CGASEG 0x0b800          // color video memory segment
  62.  
  63. #define BUFFERSIZE 4096         // maximum size of the file buffer
  64. #define MAXLINE    255          // default maximum size of a line
  65.  
  66. long buffoffset;            // offset into buffer of current line
  67. long fsize;                 // file size in bytes
  68. int  bufftop, buffbot;      // first and last character in buffer
  69. int  wintop, winbot;        // first and last character in window
  70. int  winrow, wincol;        // row and column of window highlight
  71. int  sline, eline;          // start and end line of window
  72. int  scol, ecol;            // start and end col of window
  73. int  height, width;         // height and width of window
  74. int  infile;                // input file handle
  75. int  maxlin;                // line size
  76. int  buffsize;              // buffer size
  77. int  hlight;                // highlight attribute
  78. int  norm;                  // normal attribute
  79. int  kcount;                // number of keys in terminate key list
  80. int  colinc;                // col increment amount
  81. int  brows;                 // browse flag
  82. char refresh;               // YES means refresh screen
  83. char kstr[25];              // terminate key string
  84.  
  85. char far *buffer;           // file buffer pointer
  86. char far *lbuff;            // line buffer pointer
  87. char far *vseg;             // video segment variable
  88.  
  89.  
  90.     // prototypes
  91.  
  92.  
  93. CLIPPER _ft_dfinit(void);
  94. CLIPPER _ft_dfclos(void);
  95.  
  96. unsigned char keyin(void);
  97. void          chattr(int x, int y, int len, int attr);
  98. long          getblock(long offset);
  99. void          buff_align(void);
  100. void          win_align(void);
  101. void          disp_update(int offset);
  102. void          windown(void);
  103. void          winup(void);
  104. void          linedown(void);
  105. void          lineup(void);
  106. void          filetop(void);
  107. void          filebot(void);
  108.  
  109.     // found in dispa.asm
  110.  
  111. int           _ft_fileread(int handle, char far *buffer, int bytes);
  112. long          _ft_fileseek(int handle, long offset, int direction);
  113. void          _ft_gotoxy(int x, int y);
  114. char          _ft_getkey(void);
  115. char far *    _ft_vconfig(void);
  116.  
  117.     // this is defined because I found out that CLIPPER has a version
  118.     //   strcpy linked in normally - this just shut's up the LINT check
  119.  
  120. extern char *strcpy(char far *, char far *);
  121.  
  122.  
  123. /*
  124.  * chattr() replace the color attribute with a new one starting at
  125.  * location x, y and going for length len.
  126.  *
  127.  */
  128.  
  129.  
  130. static void chattr(int x, int y, int len, int attr)
  131. {
  132.     int i;
  133.     char far *vmem;
  134.  
  135.     vmem = vseg;
  136.     FP_OFF(vmem) = (y * 160) + (x * 2) + 1;     // calc the screen memory coord
  137.  
  138.     for (i = 0; i <= len; i++, vmem += 2)       // write the new attribute value
  139.         *vmem = (char) attr;
  140. }
  141.  
  142.  
  143.  
  144.  
  145. /*
  146.  *  keyin() gets the next key typed and does any translation needed.
  147.  *  Some keys are converted to a common name - like the up arrow is
  148.  *  converted to the UP value which also is the Ctrl-E value.  This
  149.  *  allows the Wordstar-like control keys to be used.  Only extended
  150.  *  keys are translated - the values of the defines were chosen to
  151.  *  match up with the non-extended key codes.
  152.  *
  153.  */
  154.  
  155. static unsigned char keyin()
  156. {
  157.     unsigned char ch;
  158.  
  159.     ch = (unsigned char) _ft_getkey();      // get the next key
  160.  
  161.     if ( ch == 0x00 )                       // check to see if it's extended
  162.     {
  163.         ch = (unsigned char) _ft_getkey();  // if so, read the second part
  164.  
  165.         switch ( ch )                       //  and convert it
  166.         {
  167.             case 75   : ch = LFT;    break;
  168.             case 77   : ch = RGT;    break;
  169.             case 72   : ch = UP;     break;
  170.             case 80   : ch = DN;     break;
  171.             case 71   : ch = HOME;   break;
  172.             case 79   : ch = ENND;   break;
  173.             case 73   : ch = PGUP;   break;
  174.             case 81   : ch = PGDN;   break;
  175.             case 62   : ch = F4;     break;
  176.             case 117  : ch = CENND;  break;
  177.             case 119  : ch = CHOME;  break;
  178.             case 118  : ch = CPGDN;  break;
  179.             case 132  : ch = CPGUP;  break;
  180.             case 116  : ch = CRGT;   break;
  181.             case 115  : ch = CLFT;   break;
  182.             case 82   : ch = INS;    break;
  183.             case 83   : ch = DEL;    break;
  184.             case 68   : ch = F0;     break;
  185.             case 59   : ch = F1;     break;
  186.             case 60   : ch = F2;     break;
  187.             case 61   : ch = F3;     break;
  188.             case 63   : ch = F5;     break;
  189.             case 64   : ch = F6;     break;
  190.             case 65   : ch = F7;     break;
  191.             case 66   : ch = F8;     break;
  192.             case 67   : ch = F9;     break;
  193.             case 113  : ch = AF0;    break;
  194.             case 104  : ch = AF1;    break;
  195.             case 105  : ch = AF2;    break;
  196.             case 106  : ch = AF3;    break;
  197.             case 107  : ch = AF4;    break;
  198.             case 108  : ch = AF5;    break;
  199.             case 109  : ch = AF6;    break;
  200.             case 110  : ch = AF7;    break;
  201.             case 111  : ch = AF8;    break;
  202.             case 112  : ch = AF9;    break;
  203.             case 94   : ch = CF1;    break;
  204.             case 95   : ch = CF2;    break;
  205.             case 96   : ch = CF3;    break;
  206.             case 97   : ch = CF4;    break;
  207.             case 98   : ch = CF5;    break;
  208.             case 99   : ch = CF6;    break;
  209.             case 100  : ch = CF7;    break;
  210.             case 101  : ch = CF8;    break;
  211.             case 102  : ch = CF9;    break;
  212.             case 103  : ch = CF0;    break;
  213.             case 120  : ch = ALT1;   break;
  214.             case 121  : ch = ALT2;   break;
  215.             case 122  : ch = ALT3;   break;
  216.             case 123  : ch = ALT4;   break;
  217.             case 124  : ch = ALT5;   break;
  218.             case 125  : ch = ALT6;   break;
  219.             case 126  : ch = ALT7;   break;
  220.             case 127  : ch = ALT8;   break;
  221.             case 128  : ch = ALT9;   break;
  222.             case 129  : ch = ALT0;   break;
  223.             case 130  : ch = ADASH;  break;
  224.             case 131  : ch = AEQL;   break;
  225.             case 30   : ch = ALTA;   break;
  226.             case 48   : ch = ALTB;   break;
  227.             case 46   : ch = ALTC;   break;
  228.             case 32   : ch = ALTD;   break;
  229.             case 18   : ch = ALTE;   break;
  230.             case 33   : ch = ALTF;   break;
  231.             case 34   : ch = ALTG;   break;
  232.             case 35   : ch = ALTH;   break;
  233.             case 23   : ch = ALTI;   break;
  234.             case 36   : ch = ALTJ;   break;
  235.             case 37   : ch = ALTK;   break;
  236.             case 38   : ch = ALTL;   break;
  237.             case 50   : ch = ALTM;   break;
  238.             case 49   : ch = ALTN;   break;
  239.             case 24   : ch = ALTO;   break;
  240.             case 25   : ch = ALTP;   break;
  241.             case 16   : ch = ALTQ;   break;
  242.             case 19   : ch = ALTR;   break;
  243.             case 31   : ch = ALTS;   break;
  244.             case 20   : ch = ALTT;   break;
  245.             case 22   : ch = ALTU;   break;
  246.             case 47   : ch = ALTV;   break;
  247.             case 17   : ch = ALTW;   break;
  248.             case 45   : ch = ALTX;   break;
  249.             case 21   : ch = ALTY;   break;
  250.             case 44   : ch = ALTZ;   break;
  251.             default   : ch = 0;      break;
  252.         }
  253.     }
  254.  
  255.     return ( ch );
  256. }
  257.  
  258.  
  259.  
  260.  
  261.  
  262. /*
  263.  * function getblock() reads the text file and returns the a block.
  264.  *  the variables offset and buffsize tell it where to start reading and
  265.  *  how many bytes to try to read.  if the block read in would not fill
  266.  *  the buffer then the offset is adjusted so that the start or end of
  267.  *  of the file is positioned at the head or tail of the buffer.
  268.  *
  269.  * it returns the offset into the file of the first byte of the buffer.
  270.  *
  271.  */
  272.  
  273. static long getblock(long offset)
  274. {
  275.  
  276.         // set the file pointer to the proper offset
  277.         //  and if an error occured then check to see
  278.         //  if a positive offset was requested, if so
  279.         //  then set the pointer to the offset from
  280.         //  the end of the file, otherwise set it from
  281.         //  the beginning of the file.
  282.  
  283.     _ft_fileseek(infile, offset, SEEK_SET);
  284.  
  285.         // read in the file and set the buffer bottom variable equal
  286.         //  to the number of bytes actually read in.
  287.  
  288.     buffbot = _ft_fileread(infile, buffer, buffsize);
  289.  
  290.         // if a full buffer's worth was not read in, make it full.
  291.  
  292.     if (( buffbot != buffsize ) && ( fsize > buffsize ))
  293.     {
  294.         if ( offset > 0 )
  295.             _ft_fileseek(infile, (long) -buffsize, SEEK_END);
  296.         else
  297.             _ft_fileseek(infile, (long) buffsize, SEEK_SET);
  298.  
  299.         buffbot = _ft_fileread(infile, buffer, buffsize);
  300.     }
  301.  
  302.         // return the actual file position */
  303.  
  304.     return(_ft_fileseek(infile, 0L, SEEK_CUR) - buffbot);
  305. }
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312. /*
  313.  * buff_align makes sure the buffer top and bottom variables point
  314.  * to actual complete lines of text.
  315.  *
  316.  */
  317.  
  318. static void buff_align()
  319. {
  320.     int i;
  321.  
  322.     bufftop = 0;
  323.     buffbot = buffsize;
  324.  
  325.     if ( buffoffset != 0L )     // if the buffoffset is otherthan 0
  326.     {
  327.         i = bufftop;            // start at the top of the file and scan
  328.                                 // forward until a CR is reached.
  329.  
  330.         while (( buffer[i] != CR ) && ( i < buffbot ))
  331.             i++;
  332.  
  333.         bufftop = i + 2;        // skip past the CR/LF to the first char
  334.     }
  335.  
  336.         // if the buffer offset is not a complete */
  337.         // buffer's length away from the file end */
  338.  
  339.     if ( buffoffset + ((long) buffbot) != fsize )
  340.     {
  341.             // if the file position of the last byte
  342.             //  of the buffer would end up past the
  343.             //  end of the file, then the buffer does
  344.             //  contain a complete buffer full and the
  345.             //  buffer end pointer needs to be set to
  346.             //  the last character of the file.
  347.  
  348.         if ( buffoffset + ((long) buffbot) > fsize )
  349.             buffbot = (int) (fsize - buffoffset);
  350.  
  351.         i = buffbot;            // point the end of the buffer to a valid
  352.                                 // complete text line.
  353.  
  354.         while (( buffer[i] != CR ) && ( i > bufftop ))
  355.             i--;
  356.  
  357.         buffbot = i + 2;        // skip past the CR/LF to the first char   */
  358.     }
  359. }
  360.  
  361.  
  362.  
  363.  
  364.  
  365. /*
  366.  * win_align takes the value for wintop and then figures out where
  367.  * winbot would be.  if winbot would extend past the end of the
  368.  * buffer, then the top of the window is adjusted to ensure that a full
  369.  * screen of text will appear.  This simplifies the cursor routines.
  370.  *
  371.  */
  372.  
  373. static void win_align()
  374. {
  375.     int i;
  376.  
  377.     winbot = wintop;            // find out if there is enough text for
  378.     i      = 0;                 // full window.
  379.  
  380.     while (( winbot < buffbot ) && ( i < height ))
  381.     {
  382.         if ( buffer[winbot] == CR )
  383.             i++;
  384.         winbot++;
  385.     }
  386.  
  387.     if ( i < height )           // if there is not a full window,
  388.     {
  389.         while ( buffer[winbot] != LF )      // then retrofit winbot
  390.             winbot--;                       // to the end of a line
  391.  
  392.         wintop = winbot;
  393.         i      = 0;                         // and setup wintop
  394.  
  395.         while (( wintop > bufftop ) && ( i <= height ))
  396.         {
  397.             if ( buffer[wintop] == LF )
  398.                 i++;
  399.             wintop--;
  400.         }
  401.  
  402.         if ( wintop != bufftop )
  403.             wintop += 2;
  404.     }
  405. }
  406.  
  407.  
  408.  
  409.  
  410.  
  411. /*
  412.  * this routine displays the actual text in the window.  This is done
  413.  * by taking each line and placing it in a string.  the screen line
  414.  * is then taken from the appropriate group of characters in the string.
  415.  * this allows a window to page left-right across the buffer without
  416.  * having to use any complex algorithm to calc the needed chars.
  417.  *
  418.  */
  419.  
  420. static void disp_update(int offset)
  421. {
  422.     int line, col, pos, i;
  423.     char far *vmem;
  424.  
  425.     vmem = vseg;
  426.  
  427.     refresh = NO;
  428.     line        = 0;
  429.  
  430.     while ( line < height )
  431.     {
  432.             // calculate the initial position, this save execution
  433.             // time because each column is considered as a offset
  434.             // from the line start
  435.  
  436.         pos = ((sline + line) * 160) + (scol * 2);
  437.  
  438.             // copy string to temp buffer
  439.  
  440.         for (i = 0; buffer[offset] != CR && offset <= winbot; offset++)
  441.         {
  442.             if ( i <= maxlin )
  443.                 lbuff[i++] = buffer[offset];
  444.         }
  445.  
  446.         for (; i <= maxlin; i++)        // fill out with spaces
  447.             lbuff[i] = ' ';
  448.  
  449.             // place the proper characters onto the screen
  450.  
  451.         for (i = wincol, col = 0; col <= width; col++)
  452.         {
  453.             FP_OFF(vmem) = pos + (col * 2);
  454.  
  455.             *vmem = lbuff[i++];
  456.         }
  457.  
  458.         line   += 1;
  459.         offset += 2;
  460.     }
  461. }
  462.  
  463.  
  464.  
  465.  
  466.  
  467. /*
  468.  * move the window pointers so that a new window's worth of information
  469.  * is visible.  it adjusts the pointers within the buffer and if necessary
  470.  * it calls the getblock function to load in a new buffer
  471.  *
  472.  */
  473.  
  474. static void winup()
  475. {
  476.     int  k;
  477.     long i, j;
  478.  
  479.     refresh = YES;
  480.     k       = wintop - 3;
  481.  
  482.     while (( buffer[k] != CR ) && ( k > bufftop ))
  483.         k--;
  484.  
  485.     if ( k >= bufftop )
  486.     {
  487.         if ( buffer[k] == CR )
  488.             k += 2;
  489.  
  490.         wintop = k;
  491.         k      = winbot - 3;
  492.  
  493.         while ( buffer[k] != CR )
  494.             k--;
  495.  
  496.         winbot = k + 2;
  497.     }
  498.     else
  499.         if ( ((long) bufftop) + buffoffset > 0 && fsize > buffsize )
  500.         {
  501.             i = buffoffset + wintop;
  502.             j = buffoffset - ((long) (buffsize / 2));
  503.  
  504.             if ( j < 0 )
  505.                 j = 0;
  506.  
  507.             buffoffset = getblock(j);
  508.             wintop     = ((int) (i - buffoffset));
  509.  
  510.             buff_align();
  511.             win_align();
  512.         }
  513. }
  514.  
  515.  
  516.  
  517.  
  518.  
  519. /*
  520.  * move the window pointers so that a new window's worth of information
  521.  * is visible.  it adjusts the pointers within the buffer and if necessary
  522.  * it calls the getblock function to load in a new buffer
  523.  *
  524.  */
  525.  
  526. static void windown()
  527. {
  528.     int  k;
  529.     long i, j;
  530.  
  531.     refresh = YES;
  532.     k       = winbot;
  533.  
  534.     while (( buffer[k] != CR ) && ( k <= buffbot ))
  535.         k++;
  536.  
  537.     k += 2;
  538.  
  539.     if ( k <= buffbot )
  540.     {
  541.         winbot = k;
  542.         k      = wintop;
  543.  
  544.         while ( buffer[k] != CR )
  545.             k++;
  546.  
  547.         wintop = k + 2;
  548.     }
  549.     else
  550.         if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize)
  551.         {
  552.             i = buffoffset + wintop;
  553.             j = i;
  554.  
  555.             if ( j > fsize )
  556.                 j = fsize - ((long) buffsize);
  557.  
  558.             buffoffset = getblock(j);
  559.  
  560.             if ( i < buffoffset )
  561.                 wintop = 0;
  562.             else
  563.                 wintop = ((int) (i - buffoffset));
  564.  
  565.             buff_align();
  566.             win_align();
  567.         }
  568. }
  569.  
  570.  
  571.  
  572.  
  573.  
  574. /* move the cursor one line down */
  575.  
  576. static void linedown()
  577. {
  578.     if ( winrow < eline )   // if cursor not at last line
  579.         winrow += 1;
  580.     else                            // otherwise adjust the window top variable
  581.         windown();
  582. }
  583.  
  584.  
  585.  
  586.  
  587.  
  588. /* move the cursor one line up */
  589.  
  590. static void lineup()
  591. {
  592.     if ( winrow > sline )
  593.         winrow -= 1;
  594.     else
  595.         winup();
  596. }
  597.  
  598.  
  599.  
  600.  
  601.  
  602. /* go to the top of the file */
  603.  
  604. static void filetop()
  605. {
  606.     if ( buffoffset != 0 )
  607.     {
  608.         buffoffset = getblock(0L);
  609.  
  610.         buff_align();
  611.     }
  612.  
  613.     refresh = YES;
  614.     wintop  = (int) buffoffset;
  615.     winrow  = sline;
  616.     wincol  = 0;
  617.  
  618.     win_align();
  619. }
  620.  
  621.  
  622.  
  623.  
  624.  
  625. /* goto the bottom of the file */
  626.  
  627. static void filebot()
  628. {
  629.     if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize )
  630.     {
  631.         buffoffset = getblock(fsize + 1);
  632.  
  633.         buff_align();
  634.     }
  635.  
  636.     refresh = YES;
  637.     wintop  = buffbot - 3;
  638.     winrow  = eline;
  639.     wincol  = 0;
  640.  
  641.     win_align();
  642. }
  643.  
  644.  
  645. CLIPPER _ft_dfinit()
  646. {
  647.     int rval, i, j;
  648.  
  649.     rval = 0;
  650.  
  651.     vseg = MK_FP(_ft_vconfig(), 0x0000);    // get video segment
  652.  
  653.     maxlin   = _parni(12);
  654.     buffsize = _parni(13);                  // yes - load value
  655.  
  656.     buffer = _xalloc(buffsize);             // allocate memory
  657.     lbuff  = _xalloc(maxlin);               //  for buffers
  658.  
  659.     if (( buffer == NULL ) || ( lbuff == NULL ))    // memory allocated?
  660.     {
  661.         rval = 8;                   // return error code 8 (memory)
  662.     }
  663.     else                            // get parameters
  664.     {
  665.         infile = _parni(1);                 // file handle
  666.         sline  = _parni(2);                 // top row of window
  667.         scol   = _parni(3);                 // left col
  668.         eline  = _parni(4);                 // bottom row
  669.         ecol   = _parni(5);                 // right col
  670.         j      = _parni(6);                 // starting line value
  671.         norm   = _parni(7);                 // normal color attribute
  672.         hlight = _parni(8);                 // highlight color attribute
  673.  
  674.         strcpy(kstr, _parc(9));             // get exit key list
  675.  
  676.         brows = _parl(10);                  // get browse flag
  677.  
  678.         colinc = _parni(11);                // column skip value
  679.  
  680.         width  = ecol - scol;               // calc width of window
  681.         height = eline - sline + 1;         // calc height of window
  682.  
  683.  
  684.         kcount     = strlen(kstr);          // get # of exit keys in list
  685.         bufftop    = 0;                     // init buffer top pointer
  686.         buffbot    = buffsize;              // init buffer bottom pointer
  687.         buffoffset = 0;                     // curr line offset into buffer
  688.         winrow     = sline;                 // init window row
  689.         wincol     = 0;                     // init window col
  690.         wintop     = 0;                     // init window top pointer
  691.         winbot     = 0;                     // init window bottom pointer
  692.  
  693.             // get file size
  694.  
  695.         fsize = _ft_fileseek(infile, 0L, SEEK_END) - 1;
  696.  
  697.             // get the first block
  698.  
  699.         _ft_fileseek(infile, 0L, SEEK_SET);
  700.  
  701.             // if block less than buffsize
  702.  
  703.         if ( fsize < ((long) buffbot) )
  704.             buffbot = (int) fsize;          // then set buffer bottom
  705.  
  706.             // set the current lines buffer offset pointer
  707.  
  708.         buffoffset = getblock((long) bufftop);
  709.  
  710.             // align buffer and window pointer to valid values
  711.  
  712.         buff_align();
  713.         win_align();
  714.  
  715.             // point line pointer to line passed by caller
  716.  
  717.         for (i = 1; i < j; i++)
  718.             linedown();
  719.  
  720.     }
  721.  
  722.     _retni(rval);
  723. }
  724.  
  725. CLIPPER _ft_dfclos()
  726. {
  727.     _xfree(buffer);     // free up allocated buffer memory
  728.     _xfree(lbuff);
  729. }
  730.  
  731.  
  732. /*  $DOC$
  733.  *  $FUNCNAME$
  734.  *     FT_DISPFILE()
  735.  *  $CATEGORY$
  736.  *     File I/O
  737.  *  $ONELINER$
  738.  *     Browse a text file
  739.  *  $SYNTAX$
  740.  *     FT_DISPFILE() -> cExitkey
  741.  *  $ARGUMENTS$
  742.  *     None
  743.  *  $RETURNS$
  744.  *     The ASCII keystroke that terminated FT_DISPFILE()
  745.  *  $DESCRIPTION$
  746.  *     This routine displays a text file within a defined window using as
  747.  *     little memory as possible.  The text file to display has to be
  748.  *     present or an error value of 0 is returned (as a character.)
  749.  *
  750.  *     Assumptions: The routine assumes that all lines are terminated
  751.  *                  with a CR/LF sequence (0x0d and 0x0a).
  752.  *
  753.  *     Note:        Make sure you allocate a buffer large enough to hold
  754.  *                  enough data for the number of lines that you have
  755.  *                  in the window.  Use the following formula as a
  756.  *                  guideline - buffer size = (# of line) + 1 * RMargin
  757.  *                  this is the smallest you should make the buffer and
  758.  *                  for normal use I recommend 4096 bytes.
  759.  *
  760.  *     Cursor Keys: Up, Down    - moves the highlight line
  761.  *                  Left, Right - moves the window over nColSkip col's
  762.  *                  Home        - moves the window to the far left
  763.  *                  End         - moves the window to the nRMargin column
  764.  *                  PgUp, PgDn  - moves the highlight one page
  765.  *                  Ctrl-PgUp   - moves the highlight to the file top
  766.  *                  Ctrl-PgDn   - moves the highlight to the file bottom
  767.  *                  Ctrl-Right  - moves the window 16 col's to the right
  768.  *                  Ctrl-Left   - moves the window 16 col's to the left
  769.  *
  770.  *                  Esc, Return - terminates the function
  771.  *
  772.  *                  All other keys are ignored unless they are specified
  773.  *                  within cExitKeys parameter.  This list will tell the
  774.  *                  routine what keys terminate the function.  Special
  775.  *                  keys must be passed by a unique value and that value
  776.  *                  can be found by looking in the keys.h file.
  777.  *  $EXAMPLES$
  778.  *     @ 4,9 TO 11,71
  779.  *
  780.  *     FT_DFSETUP("test.txt", 5, 10, 10, 70, 1, 7, 15,;
  781.  *                 "AaBb" + Chr(143), .T., 5, 132, 4096)
  782.  *
  783.  *     cKey = FT_DISPFILE()
  784.  *                         
  785.  *     FT_DFCLOSE()
  786.  *
  787.  *     @ 20,0 SAY "Key that terminated FT_DISPFILE() was: " + '[' + cKey + ']'
  788.  *  $SEEALSO$
  789.  *     FT_DFSETUP() FT_DFCLOSE()
  790.  *  $END$
  791.  */
  792.  
  793. CLIPPER FT_DISPFIL( void )
  794. {
  795.     int  i, done;
  796.     char rval[2];
  797.  
  798.     unsigned char ch;
  799.  
  800.     done    = NO;
  801.     refresh = YES;
  802.  
  803.         // draw inside of window with normal color attribute
  804.  
  805.     for (i = sline; i <= eline; i++)
  806.         chattr(scol, i, width, norm);
  807.  
  808.         // main processing loop -- terminated by user key press
  809.  
  810.     do
  811.     {
  812.         if ( refresh == YES )           // redraw window contents?
  813.             disp_update(wintop);
  814.  
  815.             // if not browse, highlight the current line
  816.  
  817.         if ( brows == NO )
  818.             chattr(scol, winrow, width, hlight);
  819.  
  820.         _ft_gotoxy(scol, winrow);       // adjust cursor
  821.  
  822.         ch = keyin();                   // get user key press
  823.  
  824.             // if not browse, then un-highlight current line
  825.  
  826.         if ( brows == NO )                  
  827.             chattr(scol, winrow, width, norm);
  828.  
  829.             // figure out what the user wants to do
  830.  
  831.         switch (ch)
  832.         {
  833.              case DN    : if ( brows == YES )           // if browse flag
  834.                               winrow = eline;           // is set, force
  835.                                                         // active line to
  836.                           linedown();                   // be last line
  837.                           break;
  838.  
  839.              case UP    : if ( brows == YES )           // if browse flag
  840.                               winrow = sline;           // is set, force
  841.                                                         // active line to
  842.                           lineup();                     // be first line
  843.                           break;
  844.  
  845.              case LFT   : wincol -= colinc;             // move cursor
  846.                           refresh = YES;                // to the left
  847.  
  848.                           if ( wincol < 0 )
  849.                               wincol = 0;
  850.  
  851.                           break;
  852.  
  853.              case RGT   : wincol += colinc;             // move cursor
  854.                           refresh = YES;                // to the right
  855.  
  856.                           if ( wincol > (maxlin - width) )
  857.                               wincol = maxlin - width;
  858.  
  859.                           break;
  860.  
  861.              case HOME  : wincol  = 0;                  // move cursor
  862.                           refresh = YES;                // to first col
  863.  
  864.                           break;
  865.  
  866.                 // move cursor to last col
  867.  
  868.              case ENND  : wincol  = maxlin - width; 
  869.                           refresh = YES;
  870.  
  871.                           break;
  872.  
  873.              case CLFT  : wincol -= 16;                 // move cursor
  874.                           refresh = YES;                // 16 col to left
  875.  
  876.                           if ( wincol < 0 )
  877.                               wincol = 0;
  878.  
  879.                           break;
  880.  
  881.              case CRGT  : wincol += 16;                 // move cursor
  882.                           refresh = YES;                // 16 col to right
  883.  
  884.                           if ( wincol > (maxlin - width) )
  885.                               wincol = maxlin - width;
  886.  
  887.                           break;
  888.  
  889.              case PGUP  : for (i = 0; i < height; i++)  // move window
  890.                               winup();                  // up one page
  891.  
  892.                           break;
  893.  
  894.              case PGDN  : for (i = 0; i < height; i++)  // move window
  895.                               windown();                // down 1 page
  896.  
  897.                           break;
  898.  
  899.              case CPGUP : filetop();                    // move cursor to
  900.                           break;                        // to top of file
  901.  
  902.              case CPGDN : filebot();                    // move cursor to
  903.                           break;                        // to bot of file
  904.  
  905.              case RET   : done = YES;                   // carriage return
  906.                           break;                        // terminates
  907.  
  908.              case ESC   : done = YES;                   // escape key
  909.                           break;                        // terminates
  910.  
  911.                 // scan key list and see if key pressed is there
  912.  
  913.              default    : for (i = 0; i <= kcount; i++) 
  914.                               if ( kstr[i] == (char) ch )
  915.                                   done = YES;
  916.                           break;                        // if so terminate
  917.         }
  918.     } while ( done == NO );
  919.  
  920.         // store the key pressed as a character to be returned
  921.  
  922.     rval[0] = (char) ch;
  923.     rval[1] = '\0';
  924.     
  925.         // return key value to caller
  926.  
  927.     _retc(rval);
  928. }
  929.